package com.jc.oms.shiro;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.CannotGetMongoDbConnectionException;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jc.business.user.UserBusiness;
import com.jc.common.util.JSONUtil;
import com.jc.common.util.NetworkUtil;
import com.jc.ds.model.User;
import com.jc.framework.util.WebConstants;

public class RetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher {
	private int								retryCount	= 5;
	private Cache<String, AtomicInteger>	passwordRetryCache;
	
	@Autowired
	private UserBusiness					userBusiness;

	public int getRetryCount() {
		return retryCount;
	}

	public void setRetryCount(int retryCount) {
		this.retryCount = retryCount;
	}

	public RetryLimitHashedCredentialsMatcher(CacheManager cacheManager) {
		passwordRetryCache = cacheManager.getCache("passwordRetryCache");
	}
	
	@Override
	public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
		HttpServletRequest request = getRequest();
		String username = (String) token.getPrincipal();
		//retry count + 1
		AtomicInteger retryCount = passwordRetryCache.get(username);
		if (retryCount == null) {
			retryCount = new AtomicInteger(0);
			passwordRetryCache.put(username, retryCount);
		}
		if (retryCount.incrementAndGet() > getRetryCount()) { throw new ExcessiveAttemptsException(); }
		boolean matches = super.doCredentialsMatch(token, info);

		try {
			String ipAddr = getIpAddr(request);
			JSONObject tokenJson = JSONUtil.toFastJson(token);
			AtomicInteger ipAtomicInteger = passwordRetryCache.get(ipAddr);
			if (ipAtomicInteger == null) {
				ipAtomicInteger = new AtomicInteger(0);
				passwordRetryCache.put(ipAddr, ipAtomicInteger);
			}
			if (matches) {
				//clear retry count
				passwordRetryCache.remove(username);
				tokenJson.remove("password");
				tokenJson.remove("credentials");
				User u = userBusiness.findByUserName(username);
				SecurityUtils.getSubject().getSession().setAttribute(WebConstants.CURRENT_USER, u);
			} else {
				List<String> passwordList = JSON.parseArray(tokenJson.getString("password"), String.class);
				String password = "";
				for (String string : passwordList) {
					password += string;
				}
				tokenJson.put("password", password);
				List<String> credentialsList = JSON.parseArray(tokenJson.getString("credentials"), String.class);
				String credentials = "";
				for (String string : credentialsList) {
					credentials += string;
				}
				tokenJson.put("credentials", credentials);
			}
			
		} catch (CannotGetMongoDbConnectionException e) {
			System.err.println(e.getClass().getName());
			System.err.println(e.getMessage());
			throw e;
		}
		return matches;
	}

	protected String getIpAddr(HttpServletRequest request) {
		return NetworkUtil.getIpAddress(request);
	}

	private HttpServletRequest getRequest() {
		return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
	}
}
